﻿using FileToVideo.Config;
using FileToVideo.Helpers;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace FileToVideo.VideoHelpers
{
    /// <summary>
    /// 视频工具类
    /// <br/>
    /// 默认:
    /// 编码格式 H264
    /// 帧数 10
    /// 分辨率 1920*1080
    /// </summary>
    public class VideoTools
    {
        /// <summary>
        /// 是否是写入模式
        /// </summary>
        private bool _isWrite;

        /// <summary>
        /// 锁对象
        /// </summary>
        private readonly object _lock = new object();

        /// <summary>
        /// 写入对象
        /// </summary>
        private VideoWriter? writer;

        /// <summary>
        /// 读取对象
        /// </summary>
        private VideoCapture? _capture;

        /// <summary>
        /// 视频帧列表
        /// </summary>
        private List<Bitmap> _frames = new List<Bitmap>();

        /// <summary>
        /// 视频路径
        /// </summary>
        private string path;

        /// <summary>
        /// 帧率
        /// </summary>
        private int fps = 10;

        /// <summary>
        /// 是否是写入模式
        /// </summary>
        public bool IsWrite { get { return _isWrite; } }

        /// <summary>
        /// 帧率
        /// </summary>
        public int FPS { get { return fps; } }

        /// <summary>
        /// 视频所在地址
        /// </summary>
        public string Path { get { return path; } }

        /// <summary>
        /// 视频工具类
        /// </summary>
        public VideoTools(bool isWrite, string path)
        {
            _isWrite = isWrite;
            this.path = path;
            if (_isWrite)
            {
                writer = new VideoWriter(path, FourCC.H264, fps, new OpenCvSharp.Size(Setting.width, Setting.height));
            }
            else
            {
                _capture = new VideoCapture(path);
                if (!_capture.IsOpened())
                {
                    throw new Exception("无法打开视频文件");
                }
                else
                {
                    fps = (int)_capture.Fps;
                }
            }
        }

        /// <summary>
        /// 写入帧
        /// </summary>
        /// <param name="frame"></param>
        /// <exception cref="Exception"></exception>
        public void WriteFrame(Mat frame)
        {
            lock (_lock)
            {
                if (writer != null)
                {
                    if (_isWrite)
                    {
                        writer.Write(frame);
                    }
                }
                else
                {
                    throw new Exception("未初始化写入对象");
                }
            }
        }

        /// <summary>
        /// 写入位图
        /// </summary>
        /// <param name="bitmap"></param>
        public void WriteBitmap(Bitmap bitmap)
        {
            using (Mat mat = BitmapConverter.ToMat(bitmap))
            {
                WriteFrame(mat);
            }
        }

        /// <summary>
        /// 将位图重复写入指定次数
        /// </summary>
        /// <param name="bitmap">要写入的位图</param>
        /// /// <param name="count">重复写入的次数</param>
        /// <exception cref="ArgumentException">当count小于等于0时抛出</exception>
        public void WriteBitmap(Bitmap bitmap, int count)
        {
            if (count <= 0)
            {
                throw new ArgumentException("重复次数必须大于0");
            }

            lock (_lock)
            {
                if (writer != null)
                {
                    if (_isWrite)
                    {
                        using (Mat mat = BitmapConverter.ToMat(bitmap))
                        {
                            for (int i = 0; i < count; i++)
                            {
                                writer.Write(mat);
                            }
                        }
                    }
                }
                else
                {
                    throw new Exception("未初始化写入对象");
                }
            }
        }

        /// <summary>
        /// 读取视频所有帧并转换为Bitmap列表
        /// </summary>
        /// <returns>Bitmap列表</returns>
        public List<Bitmap> ReadAllFrames()
        {
            if (_isWrite)
            {
                throw new Exception("当前为写入模式，不支持读取操作");
            }

            _frames.Clear();
            using (Mat mat = new Mat())
            {
                while (_capture != null && _capture.Read(mat))
                {
                    _frames.Add(BitmapConverter.ToBitmap(mat));
                }
            }
            return _frames;
        }

        /// <summary>
        /// 读取指定数量的帧
        /// </summary>
        /// <param name="frameCount">要读取的帧数</param>
        /// <returns>Bitmap列表</returns>
        public List<Bitmap> ReadFrames(int frameCount)
        {
            if (_isWrite)
            {
                throw new Exception("当前为写入模式，不支持读取操作");
            }

            List<Bitmap> frames = new List<Bitmap>();
            using (Mat mat = new Mat())
            {
                int count = 0;
                while (_capture != null && _capture.Read(mat) && count < frameCount)
                {
                    frames.Add(BitmapConverter.ToBitmap(mat));
                    count++;
                }
            }
            return frames;
        }

        /// <summary>
        /// 从指定索引开始读取指定数量的帧
        /// </summary>
        /// <param name="index">起始帧索引（从0开始）</param>
        /// <param name="count">要读取的帧数</param>
        /// <returns>Bitmap列表</returns>
        public List<Bitmap> ReadFrames(int index, int count)
        {
            if (_isWrite)
            {
                throw new Exception("当前为写入模式，不支持读取操作");
            }

            if (index < 0)
            {
                throw new ArgumentException("起始帧索引不能小于0");
            }

            if (count <= 0)
            {
                throw new ArgumentException("读取帧数必须大于0");
            }

            List<Bitmap> frames = new List<Bitmap>();
            using (Mat mat = new Mat())
            {
                // 定位到起始帧
                if (_capture != null)
                {
                    _capture.PosFrames = index;

                    int readCount = 0;
                    while (_capture.Read(mat) && readCount < count)
                    {
                        frames.Add(BitmapConverter.ToBitmap(mat));
                        readCount++;
                    }
                }
            }
            return frames;
        }

        /// <summary>
        /// 关闭
        /// </summary>
        public void Close()
        {
            lock (_lock)
            {
                if (IsWrite)
                {
                    writer?.Release();
                    writer?.Dispose();
                }
                else
                {
                    _capture?.Release();
                    _capture?.Dispose();
                    foreach (var frame in _frames)
                    {
                        frame.Dispose();
                    }
                    _frames.Clear();
                }
            }
        }
    }
}
